package com.supermap;

import com.supermap.adapters.MainFrameAdapter;
import com.supermap.consts.AttrConsts;
import com.supermap.data.*;
import com.supermap.data.processing.ObliquePhotogrammetry3DModelTool;
import com.supermap.dialogs.*;
import com.supermap.mapping.Layer;
import com.supermap.mapping.Layers;
import com.supermap.mapping.Map;
import com.supermap.mapping.Selection;
import com.supermap.mouseListeners.Layer3DsTreeMouseListener;
import com.supermap.mouseListeners.LayersTreeMouseListener;
import com.supermap.mouseListeners.MainPaneMouseListener;
import com.supermap.mouseListeners.WorkspaceTreeMouseListener;
import com.supermap.panes.*;
import com.supermap.ui.Action;
import com.supermap.ui.*;

import javax.swing.*;
import java.awt.Toolkit;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.io.File;

public class MainFrame extends JFrame {
    public JMenu fileMenu;
    public JMenu objectOperateMenu;
    public JMenu dataOperateMenu;
    public JMenu queryMenu;
    public JMenu projMenu;
    public JMenu analystMenu;
    public JMenu spatialStatisticsMenu;
    public JMenu transportationMenu;
    public JMenu styleSettingMenu;
    public JMenu space3DAnalystMenu;
    private JMenuItem saveWorkspaceItem;
    private JMenuItem saveAsWorkspaceItem;

    private WorkspaceTree workspaceTree;
    private JTabbedPane mainPane;
    private JSplitPane treeSplitPane;
    private JSplitPane settingPane;
    private JSplitPane dataPane;
    private JLabel mapScaledLbl;

    private Workspace workspace;

    public MainFrame() throws HeadlessException {
        Environment.setSceneAntialias(true);
        Environment.setOpenCLComputingEnabled(true);
        Environment.setCUDAComputingEnabled(true);
        Environment.setHardwareAccelerationEnable(true);
        Environment.setCurrentCulture("zh-CN");

        initialize();
    }

    public WorkspaceTree getWorkspaceTree() {
        return workspaceTree;
    }

    public JTabbedPane getMainPane() {
        return mainPane;
    }

    public JSplitPane getTreeSplitPane() {
        return treeSplitPane;
    }

    public JSplitPane getSettingPane() {
        return settingPane;
    }

    public JSplitPane getDataPane() {
        return dataPane;
    }

    public JLabel getMapScaledLabel() {
        return mapScaledLbl;
    }

    private void initialize() {
        this.setSize(1100, 800);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int x = (int) ((screenSize.getWidth() - this.getWidth()) / 2);
        int y = (int) ((screenSize.getHeight() - this.getHeight()) / 2);
        this.setLocation(x, y);
        this.setTitle("自定义地图小工具");

        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.addWindowListener(new MainFrameAdapter(this));

        initializeCore();
    }

    private void initializeCore() {
        JPanel mainPanel = (JPanel) getContentPane();
        mainPanel.setLayout(new BorderLayout());

        // 上方工具栏
        JMenuBar menuBar = new JMenuBar();
        initMenuBar(menuBar);

        int mainPanelWidth = getWidth();
        int mainPanelHeight = getHeight();
        int menuBarHeight = menuBar.getHeight();

        JSplitPane splitPane = new JSplitPane();
        splitPane.setBounds(0, menuBarHeight, mainPanelWidth, mainPanelHeight - menuBarHeight);
        splitPane.setDividerLocation(0.2);

        workspaceTree = new WorkspaceTree();
        JScrollPane workspaceTreeScrollPane = new JScrollPane(workspaceTree);

        treeSplitPane = new JSplitPane();
        treeSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
        treeSplitPane.setTopComponent(workspaceTreeScrollPane);
        treeSplitPane.setBottomComponent(null);
        treeSplitPane.setDividerLocation(mainPanelHeight / 2);

        splitPane.setLeftComponent(treeSplitPane);

        workspace = workspaceTree.getWorkspace();

        mainPane = new JTabbedPane();
        splitPane.setRightComponent(mainPane);
        mainPane.addMouseListener(new MainPaneMouseListener(mainPane, treeSplitPane));
        mainPane.addChangeListener(e -> {
            Component selectedComponent = ((JTabbedPane) e.getSource()).getSelectedComponent();
            if (selectedComponent instanceof MapControl) {
                MapControl mapControl = (MapControl) selectedComponent;
                LayersTree layersTree = new LayersTree(mapControl.getMap());
                layersTree.addMouseListener(new LayersTreeMouseListener(layersTree, dataPane, settingPane));
                treeSplitPane.setBottomComponent(new JScrollPane(layersTree));
            } else if (selectedComponent instanceof SceneControl) {
                SceneControl sceneControl = (SceneControl) selectedComponent;
                Layer3DsTree layer3DsTree = new Layer3DsTree(sceneControl.getScene());
                layer3DsTree.addMouseListener(new Layer3DsTreeMouseListener(layer3DsTree));
                treeSplitPane.setBottomComponent(new JScrollPane(layer3DsTree));
            }
            Container parent = mainPane.getRootPane().getParent();
            if (parent instanceof MainFrame) {
                MainFrame mainFrame = (MainFrame) parent;
                Helper.updateComponentsEnabled(new Component[]{mainFrame.objectOperateMenu, mainFrame.transportationMenu}, selectedComponent instanceof MapControl);
                Helper.updateComponentsEnabled(new Component[]{mainFrame.styleSettingMenu, mainFrame.space3DAnalystMenu}, selectedComponent instanceof SceneControl);
            }
        });

        dataPane = new JSplitPane();
        dataPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
        dataPane.setTopComponent(mainPane);
        dataPane.setBottomComponent(null);

        settingPane = new JSplitPane();
        settingPane.setLeftComponent(dataPane);
        settingPane.setRightComponent(null);
        splitPane.setRightComponent(settingPane);

        // 建立连接
        workspaceTree.addMouseListener(new WorkspaceTreeMouseListener(this));

        mainPanel.add(menuBar, BorderLayout.NORTH);
        mainPanel.add(splitPane, BorderLayout.CENTER);

        JPanel bottomPanel = new JPanel();
        bottomPanel.setLayout(new GridLayout());
        mapScaledLbl = new JLabel();
        bottomPanel.add(mapScaledLbl);
        mainPanel.add(bottomPanel, BorderLayout.SOUTH);

        saveAsWorkspaceItem.setEnabled(workspace != null);
    }

    private void initMenuBar(JMenuBar menuBar) {
        menuBar.setBounds(0, 0, getWidth(), 30);

        // 文件功能按钮
        initializeFileMenu(menuBar);

        // 对象操作
        initializeObjectOperateMenu(menuBar);

        // 数据
        initializeDataOperateMenu(menuBar);

        // 查询
        initializeQueryMenu(menuBar);

        // 投影
        initializeProjectionMenu(menuBar);

        // 空间分析
        initializeAnalystMenu(menuBar);

        // 空间统计分析
        initializeSpatialStatisticsMenu(menuBar);

        // 交通
        initializeTransportationMenu(menuBar);

        // 风格设置
        initializeStyleSettingMenu(menuBar);

        // 三维空间分析
        initializeTerrainAnalystMenu(menuBar);
    }

    private void initializeTerrainAnalystMenu(JMenuBar menuBar) {
        space3DAnalystMenu = new JMenu("三维空间分析 (K)");
        space3DAnalystMenu.setMnemonic(KeyEvent.VK_K);
        space3DAnalystMenu.setEnabled(false);
        Font menuFont = space3DAnalystMenu.getFont();
        space3DAnalystMenu.setFont(new Font(menuFont.getFamily(), menuFont.getStyle(), menuFont.getSize() + 2));
        menuBar.add(space3DAnalystMenu);

        JMenuItem slopeAndAspectAnalystItem = new JMenuItem("坡度坡向分析 (S)");
        slopeAndAspectAnalystItem.setMnemonic(KeyEvent.VK_S);
        slopeAndAspectAnalystItem.addActionListener(e -> {
            SlopeAndAspectAnalystPane slopeAndAspectAnalystPane = new SlopeAndAspectAnalystPane("坡度坡向分析", (SceneControl) mainPane.getSelectedComponent());
            settingPane.setRightComponent(new JScrollPane(slopeAndAspectAnalystPane));
            settingPane.setDividerLocation(settingPane.getWidth() - 220);
        });
        space3DAnalystMenu.add(slopeAndAspectAnalystItem);

        JMenuItem hypsometricAnalystItem = new JMenuItem("等值线分析 (H)");
        hypsometricAnalystItem.setMnemonic(KeyEvent.VK_H);
        hypsometricAnalystItem.addActionListener(e -> {
            HypsometricAnalystPane hypsometricAnalystPane = new HypsometricAnalystPane("等值线分析", (SceneControl) mainPane.getSelectedComponent());
            settingPane.setRightComponent(new JScrollPane(hypsometricAnalystPane));
            settingPane.setDividerLocation(settingPane.getWidth() - 220);
        });
        space3DAnalystMenu.add(hypsometricAnalystItem);

        JMenuItem floodAnalystItem = new JMenuItem("淹没分析 (F)");
        floodAnalystItem.setMnemonic(KeyEvent.VK_F);
        floodAnalystItem.addActionListener(e -> {
            FloodAnalystPane floodAnalystPane = new FloodAnalystPane("淹没分析", (SceneControl) mainPane.getSelectedComponent());
            settingPane.setRightComponent(floodAnalystPane);
            settingPane.setDividerLocation(settingPane.getWidth() - 220);
        });
        space3DAnalystMenu.add(floodAnalystItem);

        JMenuItem visibilityAnalystItem = new JMenuItem("通视分析 (V)");
        visibilityAnalystItem.setMnemonic(KeyEvent.VK_V);
        visibilityAnalystItem.addActionListener(e -> {
            Component selectedComponent = mainPane.getSelectedComponent();
            if (selectedComponent instanceof SceneControl) {
                SightlineAnalystDialog visibilityAnalystDialog = new SightlineAnalystDialog(this, "通视分析", false, (SceneControl) selectedComponent);
                visibilityAnalystDialog.setVisible(true);
            }
        });
        space3DAnalystMenu.add(visibilityAnalystItem);

        JMenuItem calculateViewShedItem = new JMenuItem("可视域分析 (C)");
        calculateViewShedItem.setMnemonic(KeyEvent.VK_C);
        calculateViewShedItem.addActionListener(e -> {
            Component selectedComponent = mainPane.getSelectedComponent();
            if (selectedComponent instanceof SceneControl) {
                Viewshed3DAnalystSettingPane viewshed3DAnalystSettingPane = new Viewshed3DAnalystSettingPane("可视域分析", (SceneControl) selectedComponent);
                settingPane.setRightComponent(new JScrollPane(viewshed3DAnalystSettingPane));
                settingPane.setDividerLocation(settingPane.getWidth() - 220);
            }
        });
        space3DAnalystMenu.add(calculateViewShedItem);

        JMenuItem skylineAnalystItem = new JMenuItem("天际线分析 (L)");
        skylineAnalystItem.setMnemonic(KeyEvent.VK_L);
        skylineAnalystItem.addActionListener(e -> {
            Component selectedComponent = mainPane.getSelectedComponent();
            if (selectedComponent instanceof SceneControl) {
                SkylineAnalystDialog skylineAnalystDialog = new SkylineAnalystDialog(this, "天际线分析", false, (SceneControl) selectedComponent);
                skylineAnalystDialog.setVisible(true);
            }
        });
        space3DAnalystMenu.add(skylineAnalystItem);
    }

    private void initializeStyleSettingMenu(JMenuBar menuBar) {
        styleSettingMenu = new JMenu("风格设置 (Y)");
        styleSettingMenu.setMnemonic(KeyEvent.VK_Y);
        styleSettingMenu.setEnabled(false);
        Font menuFont = styleSettingMenu.getFont();
        styleSettingMenu.setFont(new Font(menuFont.getFamily(), menuFont.getStyle(), menuFont.getSize() + 2));

        JMenuItem stretchSettingItem = new JMenuItem("拉伸设置 (S)");
        stretchSettingItem.setMnemonic(KeyEvent.VK_S);
        stretchSettingItem.addActionListener(e -> {
            StretchSettingDialog stretchSettingDialog = new StretchSettingDialog(this, "拉伸设置", false,
                    ((Layer3DsTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getScene());
            stretchSettingDialog.setVisible(true);
        });
        styleSettingMenu.add(stretchSettingItem);

        menuBar.add(styleSettingMenu);
    }

    private void initializeTransportationMenu(JMenuBar menuBar) {
        transportationMenu = new JMenu("交通 (T)");
        transportationMenu.setMnemonic(KeyEvent.VK_T);
        transportationMenu.setEnabled(false);
        Font menuFont = transportationMenu.getFont();
        transportationMenu.setFont(new Font(menuFont.getFamily(), menuFont.getStyle(), menuFont.getSize() + 2));

        JMenuItem buildNetworkItem = new JMenuItem("构建二维网络 (B)");
        buildNetworkItem.setMnemonic(KeyEvent.VK_B);
        buildNetworkItem.addActionListener(e -> {
            NetworkBuilderDialog networkBuilderDialog = new NetworkBuilderDialog(this, "构建二维网络", true, workspace);
            networkBuilderDialog.setVisible(true);
        });
        transportationMenu.add(buildNetworkItem);

        JMenu transportationAnalystMenu = new JMenu("路网分析 (R)");
        transportationAnalystMenu.setMnemonic(KeyEvent.VK_R);

        JMenuItem theBestPathAnalystItem = new JMenuItem("最佳路径分析");
        theBestPathAnalystItem.addActionListener(e -> {
            DatasetVector netWorkDataset = null;
            Layers layers = ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap().getLayers();
            int layersCount = layers.getCount();
            if (layersCount > 0) {
                for (int i = 0; i < layersCount; i++) {
                    Layer layer = layers.get(i);
                    Dataset dataset = layer.getDataset();
                    if (dataset.getType() == DatasetType.NETWORK) {
                        netWorkDataset = (DatasetVector) dataset;
                        break;
                    }
                }
            }
            if (netWorkDataset != null) {
                TheBestPathAnalystSettingPane theBestPathAnalystSettingPane = new TheBestPathAnalystSettingPane("最佳路径分析",
                        ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap().getMapControl(),
                        netWorkDataset, dataPane);
                settingPane.setRightComponent(new JScrollPane(theBestPathAnalystSettingPane));
                settingPane.setResizeWeight(1);
            } else {
                JOptionPane.showMessageDialog(this, "当前无已打开的网络数据地图！请先打开网络数据地图，再进行最佳路径分析",
                        "最佳路径分析", JOptionPane.WARNING_MESSAGE);
            }
        });
        transportationAnalystMenu.add(theBestPathAnalystItem);

        JMenuItem serviceAreaAnalystItem = new JMenuItem("服务区分析");
        serviceAreaAnalystItem.addActionListener(e -> {
            DatasetVector netWorkDataset = null;
            Layers layers = ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap().getLayers();
            int layersCount = layers.getCount();
            if (layersCount > 0) {
                for (int i = 0; i < layersCount; i++) {
                    Layer layer = layers.get(i);
                    Dataset dataset = layer.getDataset();
                    if (dataset.getType() == DatasetType.NETWORK) {
                        netWorkDataset = (DatasetVector) dataset;
                        break;
                    }
                }
            }
            if (netWorkDataset != null) {
                ServiceAreaAnalystSettingPane serviceAreaAnalystSettingPane = new ServiceAreaAnalystSettingPane("服务区分析",
                        ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap().getMapControl(),
                        netWorkDataset, dataPane);
                settingPane.setRightComponent(new JScrollPane(serviceAreaAnalystSettingPane));
                settingPane.setResizeWeight(1);
            } else {
                JOptionPane.showMessageDialog(this, "当前无已打开的网络数据地图！请先打开网络数据地图，再进行服务区分析",
                        "服务区分析", JOptionPane.WARNING_MESSAGE);
            }
        });
        transportationAnalystMenu.add(serviceAreaAnalystItem);

        transportationMenu.add(transportationAnalystMenu);

        menuBar.add(transportationMenu);
    }

    private void initializeSpatialStatisticsMenu(JMenuBar menuBar) {
        spatialStatisticsMenu = new JMenu("空间统计分析 (S)");
        spatialStatisticsMenu.setMnemonic(KeyEvent.VK_S);
        spatialStatisticsMenu.setEnabled(false);
        Font menuFont = spatialStatisticsMenu.getFont();
        spatialStatisticsMenu.setFont(new Font(menuFont.getFamily(), menuFont.getStyle(), menuFont.getSize() + 2));
        menuBar.add(spatialStatisticsMenu);

        JMenu clusteringAnalystMenu = new JMenu("聚类分析 (C)");
        clusteringAnalystMenu.setMnemonic(KeyEvent.VK_C);
        spatialStatisticsMenu.add(clusteringAnalystMenu);

        JMenuItem kMeansClusteringAnalystItem = new JMenuItem("K均值聚类分析");
        kMeansClusteringAnalystItem.addActionListener(e -> {
            KMeansClusteringAnalystDialog kMeansClusteringAnalystDialog = new KMeansClusteringAnalystDialog(this, "K均值聚类", true, workspace);
            kMeansClusteringAnalystDialog.setVisible(true);
            kMeansClusteringAnalystDialog.dispose();
        });
        clusteringAnalystMenu.add(kMeansClusteringAnalystItem);

        JMenuItem meanShiftClusteringAnalystItem = new JMenuItem("均值偏移聚类分析");
        meanShiftClusteringAnalystItem.addActionListener(e -> {
            MeanShiftClusteringAnalystDialog meanShiftClusteringAnalystDialog = new MeanShiftClusteringAnalystDialog(this, "均值偏移聚类", true, workspace);
            meanShiftClusteringAnalystDialog.setVisible(true);
            meanShiftClusteringAnalystDialog.dispose();
        });
        clusteringAnalystMenu.add(meanShiftClusteringAnalystItem);

        JMenu spatialRelModelingMenu = new JMenu("空间关系建模 (R)");
        spatialRelModelingMenu.setMnemonic(KeyEvent.VK_R);
        spatialStatisticsMenu.add(spatialRelModelingMenu);

        JMenuItem geographicallyAndTemporallyWeightedRegressionItem = new JMenuItem("时空地理加权回归分析");
        geographicallyAndTemporallyWeightedRegressionItem.addActionListener(e -> {
            GeographicallyAndTemporallyWeightedRegressionDialog geographicallyAndTemporallyWeightedRegressionDialog = new GeographicallyAndTemporallyWeightedRegressionDialog(this, "时空地理加权回归分析", true, workspace);
            geographicallyAndTemporallyWeightedRegressionDialog.setVisible(true);
            geographicallyAndTemporallyWeightedRegressionDialog.dispose();
        });
        spatialRelModelingMenu.add(geographicallyAndTemporallyWeightedRegressionItem);
    }

    private void initializeAnalystMenu(JMenuBar menuBar) {
        analystMenu = new JMenu("空间分析 (A)");
        analystMenu.setMnemonic(KeyEvent.VK_A);
        analystMenu.setEnabled(false);
        Font menuFont = analystMenu.getFont();
        analystMenu.setFont(new Font(menuFont.getFamily(), menuFont.getStyle(), menuFont.getSize() + 2));

        JMenuItem overlayAnalystItem = new JMenuItem("叠加分析 (O)");
        overlayAnalystItem.setMnemonic(KeyEvent.VK_O);
        overlayAnalystItem.addActionListener(e -> {
            OverlayAnalystSettingPane overlayAnalystSettingPane = new OverlayAnalystSettingPane(workspace);
            settingPane.setRightComponent(new JScrollPane(overlayAnalystSettingPane));
            settingPane.setResizeWeight(1);
        });
        analystMenu.add(overlayAnalystItem);

        JMenu bufferAnalystMenu = new JMenu("缓冲区分析 (B)");
        bufferAnalystMenu.setMnemonic(KeyEvent.VK_B);

        JMenuItem bufferAnalystItem = new JMenuItem("缓冲区分析");
        bufferAnalystItem.addActionListener(e -> {
            BufferAnalystSettingPane bufferAnalystSettingPane = new BufferAnalystSettingPane(workspace, false);
            settingPane.setRightComponent(new JScrollPane(bufferAnalystSettingPane));
            settingPane.setResizeWeight(1);
        });
        bufferAnalystMenu.add(bufferAnalystItem);

        JMenuItem multiBufferAnalystItem = new JMenuItem("多重缓冲区分析");
        multiBufferAnalystItem.addActionListener(e -> {
            BufferAnalystSettingPane bufferAnalystSettingPane = new BufferAnalystSettingPane(workspace, true);
            settingPane.setRightComponent(new JScrollPane(bufferAnalystSettingPane));
            settingPane.setResizeWeight(1);
        });
        bufferAnalystMenu.add(multiBufferAnalystItem);

        analystMenu.add(bufferAnalystMenu);

        JMenu rasterAnalystMenu = new JMenu("栅格分析 (R)");
        rasterAnalystMenu.setMnemonic(KeyEvent.VK_R);

        JMenu surfaceAnalystMenu = new JMenu("表面分析");

        JMenuItem extractAllIsoLineItem = new JMenuItem("提取所有线");
        extractAllIsoLineItem.addActionListener(e -> {
            ExtractIsoLineOrRegionSettingPane extractIsoLineOrRegionSettingPane = new ExtractIsoLineOrRegionSettingPane("提取所有线", workspace, true);
            settingPane.setRightComponent(new JScrollPane(extractIsoLineOrRegionSettingPane));
            settingPane.setResizeWeight(1);
        });
        surfaceAnalystMenu.add(extractAllIsoLineItem);

        JMenuItem extractAllIsoRegionItem = new JMenuItem("提取所有面");
        extractAllIsoRegionItem.addActionListener(e -> {
            ExtractIsoLineOrRegionSettingPane extractIsoLineOrRegionSettingPane = new ExtractIsoLineOrRegionSettingPane("提取所有面", workspace, false);
            settingPane.setRightComponent(new JScrollPane(extractIsoLineOrRegionSettingPane));
            settingPane.setResizeWeight(1);
        });
        surfaceAnalystMenu.add(extractAllIsoRegionItem);

        JMenuItem slopeAndAspectAnalystItem = new JMenuItem("坡度坡向分析");
        slopeAndAspectAnalystItem.addActionListener(e -> {
            SlopeAndAspectAnalystDialog slopeAndAspectAnalystDialog = new SlopeAndAspectAnalystDialog(this, "坡度坡向分析", false, workspace);
            slopeAndAspectAnalystDialog.setVisible(true);
        });
        surfaceAnalystMenu.add(slopeAndAspectAnalystItem);

        rasterAnalystMenu.add(surfaceAnalystMenu);

        JMenuItem rasterResamplingItem = new JMenuItem("栅格等分重采样 (E)");
        rasterResamplingItem.setMnemonic(KeyEvent.VK_E);
        rasterResamplingItem.addActionListener(e -> {
            RasterResamplingDialog rasterResamplingDialog = new RasterResamplingDialog(this, "栅格等分重采样", true, workspace);
            rasterResamplingDialog.setVisible(true);
            rasterResamplingDialog.dispose();
        });
        rasterAnalystMenu.add(rasterResamplingItem);

        analystMenu.add(rasterAnalystMenu);

        JMenuItem interpolationRBFItem = new JMenuItem("样条插值 (I)");
        interpolationRBFItem.setMnemonic(KeyEvent.VK_I);
        interpolationRBFItem.addActionListener(e -> {
            InterpolationRBFDialog interpolationRBFDialog = new InterpolationRBFDialog(this, "样条插值", true, workspace);
            interpolationRBFDialog.setVisible(true);
            interpolationRBFDialog.dispose();
        });
        analystMenu.add(interpolationRBFItem);

        menuBar.add(analystMenu);
    }

    private void initializeProjectionMenu(JMenuBar menuBar) {
        projMenu = new JMenu("投影 (P)");
        projMenu.setMnemonic(KeyEvent.VK_P);
        projMenu.setEnabled(false);
        Font menuFont = projMenu.getFont();
        projMenu.setFont(new Font(menuFont.getFamily(), menuFont.getStyle(), menuFont.getSize() + 2));

        JMenuItem projTransformItem = new JMenuItem("数据集投影转换 (T)");
        projTransformItem.setMnemonic(KeyEvent.VK_T);
        projTransformItem.addActionListener(e -> {
            ProjTransformDialog projTransformDialog = new ProjTransformDialog(this, "数据集投影转换", false, workspace, this);
            projTransformDialog.setVisible(true);
        });
        projMenu.add(projTransformItem);

        menuBar.add(projMenu);
    }

    private void initializeQueryMenu(JMenuBar menuBar) {
        queryMenu = new JMenu("查询 (Q)");
        queryMenu.setMnemonic(KeyEvent.VK_Q);
        queryMenu.setEnabled(false);
        Font menuFont = queryMenu.getFont();
        queryMenu.setFont(new Font(menuFont.getFamily(), menuFont.getStyle(), menuFont.getSize() + 2));

        // SQL查询
        JMenuItem sqlQueryItem = new JMenuItem("SQL查询 (S)");
        sqlQueryItem.setMnemonic(KeyEvent.VK_S);
        sqlQueryItem.addActionListener(e -> {
            Map map = ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap();
            if (map == null || map.getLayers().getCount() == 0) {
                return;
            }
            SqlQueryDialog sqlQueryDialog = new SqlQueryDialog(this, "SQL查询", false, map, dataPane);
            sqlQueryDialog.setVisible(true);
        });
        queryMenu.add(sqlQueryItem);

        // 空间查询
        JMenuItem spatialQueryItem = new JMenuItem("空间查询 (P)");
        spatialQueryItem.setMnemonic(KeyEvent.VK_P);
        spatialQueryItem.addActionListener(e -> {
            Map map = ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap();
            if (map == null) {
                JOptionPane.showMessageDialog(this, "请先打开地图！", "空间查询", JOptionPane.WARNING_MESSAGE);
                return;
            }
            Selection[] selections = map.findSelection(true);
            if (selections.length == 0) {
                JOptionPane.showMessageDialog(this, "空间查询需要先选中矢量对象！", "空间查询", JOptionPane.WARNING_MESSAGE);
                return;
            }

            Selection selection = selections[0];
            Recordset recordset = selection.toRecordset();
            SpatialQueryDialog spatialQueryDialog = new SpatialQueryDialog(this, "空间查询", false, map, recordset);
            spatialQueryDialog.setVisible(true);
        });
        queryMenu.add(spatialQueryItem);

        menuBar.add(queryMenu);
    }

    private void initializeDataOperateMenu(JMenuBar menuBar) {
        dataOperateMenu = new JMenu("数据 (D)");
        dataOperateMenu.setMnemonic(KeyEvent.VK_D);
        dataOperateMenu.setEnabled(false);
        Font menuFont = dataOperateMenu.getFont();
        dataOperateMenu.setFont(new Font(menuFont.getFamily(), menuFont.getStyle(), menuFont.getSize() + 2));
        menuBar.add(dataOperateMenu);

        JMenu topologyMenu = new JMenu("拓扑 (T)");
        topologyMenu.setMnemonic(KeyEvent.VK_T);
        dataOperateMenu.add(topologyMenu);

        JMenuItem topologyValidatorItem = new JMenuItem("检查几何");
        topologyValidatorItem.addActionListener(e -> {
            TopologyValidatorDialog topologyValidatorDialog = new TopologyValidatorDialog(this, "检查几何", true, workspace);
            topologyValidatorDialog.setVisible(true);
            topologyValidatorDialog.dispose();
        });
        topologyMenu.add(topologyValidatorItem);

        JMenu dataProcessingMenu = new JMenu("数据处理 (P)");
        dataProcessingMenu.setMnemonic(KeyEvent.VK_P);
        dataOperateMenu.add(dataProcessingMenu);

        JMenuItem aggregatePolygonsItem = new JMenuItem("面聚合");
        aggregatePolygonsItem.addActionListener(e -> {
            AggregatePolygonsDialog aggregatePolygonsDialog = new AggregatePolygonsDialog(this, "面聚合", true, workspace);
            aggregatePolygonsDialog.setVisible(true);
            aggregatePolygonsDialog.dispose();
        });
        dataProcessingMenu.add(aggregatePolygonsItem);

        JMenuItem entityEncodeItem = new JMenuItem("地理实体二维编码");
        entityEncodeItem.addActionListener(e -> {
            EntityEncodeDialog entityEncodeDialog = new EntityEncodeDialog(this, "地理实体二维编码", true, workspace, false);
            entityEncodeDialog.setVisible(true);
            entityEncodeDialog.dispose();
        });
        dataProcessingMenu.add(entityEncodeItem);

        JMenuItem entityEncode3DItem = new JMenuItem("地理实体三维编码");
        entityEncode3DItem.addActionListener(e -> {
            EntityEncodeDialog entityEncodeDialog = new EntityEncodeDialog(this, "地理实体三维编码", true, workspace, true);
            entityEncodeDialog.setVisible(true);
            entityEncodeDialog.dispose();
        });
        dataProcessingMenu.add(entityEncode3DItem);
    }

    private void initializeObjectOperateMenu(JMenuBar menuBar) {
        objectOperateMenu = new JMenu("对象操作 (O)");
        objectOperateMenu.setMnemonic(KeyEvent.VK_O);
        objectOperateMenu.setEnabled(false);
        Font menuFont = objectOperateMenu.getFont();
        objectOperateMenu.setFont(new Font(menuFont.getFamily(), menuFont.getStyle(), menuFont.getSize() + 2));

        // 新建对象
        JMenu createObjectMenu = new JMenu("新建对象 (C)");
        createObjectMenu.setMnemonic(KeyEvent.VK_C);

        // 点
        JMenuItem createPointItem = new JMenuItem("点");
        createPointItem.addActionListener(e -> ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap().getMapControl().setAction(Action.CREATEPOINT));
        createObjectMenu.add(createPointItem);

        // 线段
        JMenuItem createLineItem = new JMenuItem("线段");
        createLineItem.addActionListener(e -> ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap().getMapControl().setAction(Action.CREATELINE));
        createObjectMenu.add(createLineItem);

        // 折线
        JMenuItem createPolylineItem = new JMenuItem("折线");
        createPolylineItem.addActionListener(e -> ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap().getMapControl().setAction(Action.CREATEPOLYLINE));
        createObjectMenu.add(createPolylineItem);

        // 面
        JMenuItem createPolygonItem = new JMenuItem("面");
        createPolygonItem.addActionListener(e -> ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap().getMapControl().setAction(Action.CREATEPOLYGON));
        createObjectMenu.add(createPolygonItem);

        // 矩形
        JMenuItem createRectangleItem = new JMenuItem("矩形");
        createRectangleItem.addActionListener(e -> ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap().getMapControl().setAction(Action.CREATERECTANGLE));
        createObjectMenu.add(createRectangleItem);

        // 圆角矩形
        JMenuItem createRoundRectangleItem = new JMenuItem("圆角矩形");
        createRoundRectangleItem.addActionListener(e -> ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap().getMapControl().setAction(Action.CREATE_ROUND_RECTANGLE));
        createObjectMenu.add(createRoundRectangleItem);

        // 圆
        JMenuItem createCircleItem = new JMenuItem("圆");
        createCircleItem.addActionListener(e -> ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap().getMapControl().setAction(Action.CREATECIRCLE));
        createObjectMenu.add(createCircleItem);

        // 文本
        JMenuItem createTextItem = new JMenuItem("文本");
        createTextItem.addActionListener(e -> ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap().getMapControl().setAction(Action.CREATETEXT));
        createObjectMenu.add(createTextItem);

        // 沿线文本
        JMenuItem createAlongLineTextItem = new JMenuItem("沿线文本");
        createAlongLineTextItem.addActionListener(e -> ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).getMap().getMapControl().setAction(Action.CREATE_ALONG_LINE_TEXT));
        createObjectMenu.add(createAlongLineTextItem);

        objectOperateMenu.add(createObjectMenu);

        menuBar.add(objectOperateMenu);
    }

    private void initializeFileMenu(JMenuBar menuBar) {
        fileMenu = new JMenu("文件 (F)");
        fileMenu.setMnemonic(KeyEvent.VK_F);
        Font menuFont = fileMenu.getFont();
        fileMenu.setFont(new Font(menuFont.getFamily(), menuFont.getStyle(), menuFont.getSize() + 2));

        // 打开工作空间按钮
        JMenuItem openFileItem = new JMenuItem();
        openFileItem.setMnemonic(KeyEvent.VK_O);
        openFileItem.setIcon(Helper.getImageIconFromResources("OpenFileWorkspace.png"));
        openFileItem.setText("打开 (O)");
        openFileItem.setToolTipText("打开工作空间");
        openFileItem.addActionListener(e -> Helper.openWorkspaceFile(this, workspaceTree));
        fileMenu.add(openFileItem);

        // 保存工作空间按钮
        saveWorkspaceItem = new JMenuItem();
        saveWorkspaceItem.setMnemonic(KeyEvent.VK_S);
        saveWorkspaceItem.setIcon(Helper.getImageIconFromResources("SaveWorkspace.png"));
        saveWorkspaceItem.setText("保存 (S)");
        saveWorkspaceItem.setToolTipText("保存工作空间");
        saveWorkspaceItem.addActionListener(e -> {
            String caption = workspace.getCaption();
            if (caption.equals(AttrConsts.EMPTY) || caption.equals("UntitledWorkspace")) {
                saveAsWorkspaceFile();
            } else {
                workspace.save();
            }
        });
        fileMenu.add(saveWorkspaceItem);

        // 另存工作空间按钮
        saveAsWorkspaceItem = new JMenuItem();
        saveAsWorkspaceItem.setIcon(Helper.getImageIconFromResources("SaveWorkspace.png"));
        saveAsWorkspaceItem.setText("另存为");
        saveAsWorkspaceItem.setToolTipText("另存为工作空间");
        saveAsWorkspaceItem.addActionListener(e -> saveAsWorkspaceFile());
        fileMenu.add(saveAsWorkspaceItem);

        menuBar.add(fileMenu);
    }

    private void saveAsWorkspaceFile() {
        FileDialog saveAsFileDialog = new FileDialog(this, "另存为工作空间", FileDialog.SAVE);
        String workspacePath = Helper.getFilePathFromFileDialog(saveAsFileDialog, AttrConsts.WORKSPACE_FILTER);
        if (workspacePath == null) {
            return;
        }

        String[] strings = new File(workspacePath).getName().split("\\.");
        workspace.setCaption(strings[strings.length - 2]);
        WorkspaceConnectionInfo workspaceConnectionInfo = new WorkspaceConnectionInfo(workspacePath);
        if (workspace.saveAs(workspaceConnectionInfo)) {
            JOptionPane.showMessageDialog(this,
                    "工作空间另存为：" + workspacePath,
                    "另存为工作空间操作结果", JOptionPane.INFORMATION_MESSAGE);
            workspaceConnectionInfo.dispose();
            workspace.close();
            workspaceTree.reload();
            ((LayersTree) ((JScrollPane) treeSplitPane.getBottomComponent()).getViewport().getView()).reload();
        } else {
            JOptionPane.showMessageDialog(this,
                    "工作空间另存失败！",
                    "另存为工作空间操作结果", JOptionPane.ERROR_MESSAGE);
            workspaceConnectionInfo.dispose();
        }
    }

    public void windowClosing() {
        Component[] components = mainPane.getComponents();
        if (components != null && components.length > 0) {
            for (Component component : components) {
                if (component instanceof MapControl) {
                    MapControl mapControl = (MapControl) component;
                    mapControl.getMap().close();
                    mapControl.dispose();
                } else if (component instanceof SceneControl) {
                    SceneControl sceneControl = (SceneControl) component;
                    sceneControl.getScene().close();
                    sceneControl.dispose();
                }
            }
        }

        if (workspace != null) {
            workspace.close();
            workspace.dispose();
        }
    }
}
